<?php
namespace Matrix;

/**
 * 事件类
 *
 * 事件可以不更改程序代码, 而通过注册事件来控制程序运行中的各个阶段
 *
 * 注册监听器:
 * <code>
 * Event::listen('start', function() {});
 * Event::listen('start', array($obj, 'method'));
 * </code>
 * 
 * 触发事件:
 * <code>
 * Event::first('start', array('name' = 'acropolis'));
 * </code>
 *
 * 也可以注册队列事件:
 * <code>
 * Event::queue('queue', 'key', array('test'));
 * Event::flusher('queue', function() {});
 * </code>
 *
 * 触发队列事件:
 * <code>
 * Event::flush('queue');
 * </code>
 */
class Event
{
	/**
	 * 所有已经注册的事件
	 *
	 * @var array
	 */
	public static $events = array();
	
	/**
	 * 等待冲洗的队列事件
	 *
	 * @var array
	 */
	public static $queued = array();
	
	/**
	 * 所有已经注册的冲洗回调函数
	 *
	 * @var array
	 */
	public static $flushers = array();
	
	/**
	 * 检测事件是否注册有监听器
	 *
	 * @param	string	$event
	 * @return	boolean
	 */
	public static function listeners($event)
	{
		return isset(static::$events[$event]);
	}
	
	/**
	 * 为事件注册一个监听器
	 *
	 * @param	string	$event
	 * @param	mixed	$callback
	 * @return	void
	 */
	public static function listen($event, $callback)
	{
		static::$events[$event][] = $callback;
	}
	
	/**
	 * 为事件注册一个监听器, 覆盖前面的注册器
	 *
	 * @param	string	$event
	 * @param	mixed	$callback
	 * @return	void
	 */
	public static function override($event, $callback)
	{
		static::clear($event);
		static::listen($event, $callback);
	}
	
	/**
	 * 注册队列事件
	 *
	 * @param	string	$queue
	 * @param	string	$key
	 * @param	array	$data
	 * @return	void
	 */
	public static function queue($queue, $key, $data = array())
	{
		static::$queued[$queue][$key] = $data;
	}
	
	/**
	 * 注册队列冲洗回调函数
	 *
	 * @param	string	$queue
	 * @param	mixed	$callback
	 * @return	void
	 */
	public static function flusher($queue, $callback)
	{
		static::$flushers[$queue][] = $callback;
	}
	
	/**
	 * 清理事件已经事件的所有监听器
	 *
	 * @param	string	$event
	 * @return	void
	 */
	public static function clear($event)
	{
		unset(static::$events[$event]);
	}
	
	/**
	 * 触发事件, 返回第一个响应
	 *
	 * @param	string	$event
	 * @param	array	$parameters
	 * @return	mixed
	 */
	public static function first($event, $parameters = array())
	{
		return head(static::fire($event, $parameters));
	}
	
	/**
	 * 触发事件, 返回第一个响应, 执行将会终止, 在找到首个有效响应
	 *
	 * @param	string	$event
	 * @param	array	$parameters
	 * @return	mixed
	 */
	public static function until($event, $parameters = array())
	{
		return static::fire($event, $parameters, true);
	}
	
	/**
	 * 触发事件, 调用其所有监听器
	 *
	 * @param	string	$event
	 * @param	array	$parameters
	 * @param	boolean	$halt
	 * @return	array
	 */
	public static function fire($events, $parameters = array(), $halt = false)
	{
		$responses = array();
		$parameters = (array)$parameters;
		foreach ((array)$events as $event) {
			if (static::listeners($event)) {
				foreach (static::$events[$event] as $callback) {
					$response = call_user_func_array($callback, $parameters);
					if ($halt && $response !== null) {
						return $response;
					}
					$responses[] = $response;
				}
			}
		}
		return $halt ? null : $responses;
	}
	
	/**
	 * 冲洗队列事件
	 *
	 * @param	string	$queue
	 * @return	void
	 */
	public static function flush($queue)
	{
		foreach (static::$flushers[$queue] as $flusher) {
			if (!isset(static::$queued[$queue])) {
				continue;
			}
			foreach (static::$queued[$queue] as $key => $payload) {
				array_unshift($payload, $key);
				call_user_func_array($flusher, $payload);
			}
		}
	}
}